<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //函数声明
        function max(a, b) {
            return a > b ? a : b;
        }

        //函数表达式
        var max = function (a, b) {
            return a > b ? a : b;
        };

        // 构造函数创建函数对象
        var max = new Function("x","y","return x>y?x:y");
        max(2,4);

        //  单独的匿名函数是无法运行的
        // 可以把匿名函数赋值给变量或立即执行
        /**匿名函数直接写报错
         * function(){
         * 
         * }
        */ 

        // 立即执行解决
        /**
         * 书写错误
         * (function(){
         * console.log("匿名函数立即执行");
         * }(); 
        */
        (function(){
            console.log("匿名函数立即执行");
        })();

        // 把匿名函数赋值给变量
        var foo = function(){
            console.log("匿名函数必须写名字，直接声明报错")
        }
        foo();

        // 同时 赋值给变量和立即执行
        var foo = (function(){console.log("xxx");})();
        // foo(); //报错
        foo;  //对
        typeof foo; //undefined 类型是函数返回值类型
        var foo1 = (function(){console.log("xxx"); return "sss"})();
        typeof foo1; //string

        // 具名函数优势：当遇到错误时，堆栈跟踪会显示函数名，容易寻找错误
        function f1() {
            (function() {
            console.error("error");
            })();
        }
        f1();

        // name属性
        var f1 = function() {};
        console.log(f1.name); //f1

        var obj = { method: function() {} };
        console.log(obj.method.name); //method

        var f1 = new Function();
        console.log(f1.name);  //anonymous，匿名函数

        //length属性 形参个数
        function fun1(){}
        console.log(fun1.length); //0

        function fun2(a,b){}
        console.log(fun2.length); //2

        //类数组对象
        var obj = {
            0: "hello",
            1: "world",
            length: 2
        };
        console.log(obj[0]);
        console.log(obj.length);
        for (var i = 0; i < obj.length; i++) {
            console.log(obj[i]);
        }
        // 思考  obj.push("你好"); 能否执行
        // 不能
        
        // arguments 对象，代表传入函数的实参
        // 是函数中的局部变量，不能显式创建，只有函数调用时才可用
        // 它是一个类数组对象，与数组一样具有 length 与 index 属性 可以使用索引,但没有push等方法
        // 本质确实个 Object，length代表实参数量
        function fun(a,b){
            var b = b || 2; //没有输入b的值，默认为2
            console.log("a:",a);
            console.log("b:",b);
        }
        // 用arguments 
        function fun(a,b){
            var b;
            if(arguments.length != 2){
                b=2; 
            }
            console.log("a:",a);
            console.log("b:",b);
        }
        fun(1);
        fun(1,2,3);

        // arguments 与形参的“双向绑定”特性
        // arguments[i] 与 i-1个参数 相当于是同一个；
        // 当第i-1个是基本数据类型时，不影响外面；是对象时会影响
        // argument[]与参数始终是绑定在一起的！！
        //1. 实参arguments数组和形参 a b c之间的关系
        function fun(a, b, c) {
            console.log(a, b, c); //1  {x: 1, y: 2} undefined
            console.dir(arguments); //数组-0: 1;1: {x: 1, y: 2}
            console.log(a === arguments[0]); //true
            console.log(b === arguments[1]); //true
            console.log(c === arguments[2]); //true
        }
        var obj = { x: 1, y: 2 };
        fun(1, obj);

        //2. 修改第一个形参a 和实参arguments[0],观察之间的关系
        function fun(a, b, c) {
            console.log(a === arguments[0]); //true
            a = 2;
            console.log(arguments[0]); //2
            arguments[0] = 3;
            console.log(a); //3
        }
        var obj = { x: 1, y: 2 };
        fun(1, obj);

        //3. 修改第二个形参b 和实参arguments[1],观察之间的关系
        // ※ 例题 (重要)
        function fun(a, b, c) {
            console.log(b === arguments[1]); //true
            b = [1, 2, 3]; //断开了 即b和传入的参数obj不在指向同一位置
            console.log(arguments[1]); //[1, 2, 3] //b和arguments[1]还是"同一个"
            arguments[1] = [2, 3, 4];
            console.log(b); //[2, 3, 4]
        }
        var obj = { x: 1, y: 2 };
        fun(1, obj);
        console.log(obj); //思考：是[2,3,4]还是{x:1,y:2}
        // {x: 1, y: 2} 
        
    </script>
</body>
</html>